/**
 * This class represents a warehouse
 */

/**
 * @author Maximilian Csuk
 * @author Bernhard Denner
 * @author Konrad Paumann
 *
 * $Revision: 84 $
 * $Date: 2007-10-25 06:16:13 +0000 (Thu, 25 Oct 2007) $
 */
import java.util.*;
import java.io.*;


public class Warehouse implements Displayable {
	/**
	 * contains stored product groups
	 */
	private TreeMap<String, ProductGroup> assortment;
	
	/**
	 * constructor
	 */
	Warehouse() {
		assortment = new TreeMap<String, ProductGroup>();
	}
	
	/**
	 * returns a product group with a given name
	 * @param groupName name of the product group
	 * @return ProductGroup 
	 * @throws ProductException
	 */
	public ProductGroup getProductGroup(String groupName)
			throws ProductException {
		if (!assortment.containsKey(groupName)) {
			throw new ProductException("Das ist keine Produktgruppe");
		}
		return assortment.get(groupName);
	}
	
	/**
	 * adds a product group
	 * @param groupName Name of the new product group
	 * @param tax tax
	 * @throws ProductException
	 */
	public void addProductGroup(String groupName, int tax) 
			throws ProductException {
		if (assortment.containsKey(groupName)) {
			throw new ProductException("Produktgruppe schon vorhanden");
		}
		assortment.put(groupName, new ProductGroup(groupName, tax));
	}
	
	/**
	 * adds a product group
	 * @param g the group to add
	 * @throws ProductException
	 */
	public void addProductGroup(ProductGroup g) 
			throws ProductException {
		assert g != null;

		if (assortment.containsKey(g.getGroupName()))
			throw new ProductException("Produktgruppe schon vorhanden");
		
		assortment.put(g.getGroupName(), g);
	}
	
	/*
	 * removes an empty product group
	 * @param groupName
	 */
	public void removeProductGroup(String groupName) 
			throws ProductException {
		if (getProductGroup(groupName).isEmpty()) {
			if (assortment.remove(groupName) == null) {
				throw new ProductException("Produkt nicht gefunden"); 
			}
		} else {
			throw new ProductException("Produktgruppe ist noch nicht leer");
		}
	}
	
	/**
	 * adds a product
	 * 
	 * @param sDescription
	 * @param description
	 * @param price
	 * @param amount
	 * @throws ProductException
	 */
	public void addProduct(String productGroupName, String sDescription, 
			String description, int price, int amount) 
			throws ProductException {
		if (assortment.get(productGroupName).containsProduct(sDescription))
			throw new ProductException("Produkt bereits enthalten");
		assortment.get(productGroupName).addProduct(new Product(sDescription, description, price, amount));
	}
	
	/**
	 * adds a product
	 * 
	 * @param productGroupName the product-group to add the product to
	 * @param p the product to add
	 * @throws ProductException
	 */
	public void addProduct(String productGroupName, Product p) 
			throws ProductException {
		assert p != null;
		if (assortment.get(productGroupName).containsProduct(p.getShortDescription()))
			throw new ProductException("Produkt bereits enthalten");
		
		assortment.get(productGroupName).addProduct(p);
	}
	/**
	 * removes a product from warehouse
	 * @param productGroupName
	 * @param sDescription
	 * @throws ProductException
	 */
	public void removeProduct(String productGroupName, String sDescription) 
			throws ProductException {
		ProductGroup g = assortment.get(productGroupName);
		if (g == null)
			throw new ProductException("Produktgruppe exisiert nicht");
		
		g.removeProduct(sDescription);
	}
	
	/**
	 * returns an iterator for the product groups
	 * @return Iterator<ProductGroup>
	 */
	public Iterator<ProductGroup> getPgIterator() {
		return assortment.values().iterator();
	}
	
	/**
	 * gets the string to be displayed
	 * 
	 * @return String with all product-groups
	 */
	public String getDisplayString() {
		String display = new String("");
		Iterator<String> it = assortment.keySet().iterator();
		while (it.hasNext()) {
			display += assortment.get(it.next()).getDisplayString() + "\n";
		}
		return display;
	}
	
	/**
	 * returns a all products sorted by price
	 * @return String with all sorted products
	 */
	public String getSortedByPrice() {
		TreeMap<Integer, List<String>> sortedMap 
			= new TreeMap<Integer, List<String>>();
		String output = "";
		for (ProductGroup pg : assortment.values()) {
			for (Iterator<Product> it = pg.getProductIterator(); it.hasNext(); ) {
				Product p = it.next();
				String outputString = 
					pg.getGroupName() + "\t" + p.getDisplayString() + "\n";
				List<String> l = sortedMap.get(p.getPrice());
				if (l == null) {
					sortedMap.put(p.getPrice(), l = new ArrayList<String>());
				}
				l.add(outputString);
			}
		}
		
		for (List<String> l : sortedMap.values()) {
			for (String elem : l) {
				output = output + elem;
			}
		}
		return output;
	}
	
	/**
	 * returns a all products sorted by amount of products in the warehouse
	 * @return String with all sorted products
	 */
	public String getSortedByAmount() {
		TreeMap<Integer, List<String>> sortedMap 
			= new TreeMap<Integer, List<String>>();
		String output = "";
		for (ProductGroup pg : assortment.values()) {
			for (Iterator<Product> it = pg.getProductIterator(); it.hasNext(); ) {
				Product p = it.next();
				String outputString = 
					pg.getGroupName() + "\t" + p.getDisplayString() + "\n";
				List<String> l = sortedMap.get(p.getAmount());
				if (l == null) {
					sortedMap.put(p.getAmount(), l = new ArrayList<String>());
				}
				l.add(outputString);
			}
		}
	
	for (List<String> l : sortedMap.values()) {
		for (String elem : l) {
			output = output + elem;
		}
	}
	return output;
//		final Comparator<Product> AMOUNT_ORDER = 
//			new Comparator<Product>() {
//				public int compare(Product p1, Product p2) {
//					return ((Integer)p1.getAmount()).compareTo((Integer)p2.getAmount());
//			   	}
//			};
//
//		ArrayList<Product> mySortList = new ArrayList<Product>();
//		String output = "";
//		for (ProductGroup pg : assortment.values()) {
//			for (Iterator<Product> it = pg.getProductIterator(); it.hasNext(); ) {
//				Product p = it.next();
//				String outputString = 
//					pg.getGroupName() + "\t" + p.getDisplayString() + "\n";
//				mySortList.add(p);
//			}
//		}
//		Collections.sort(mySortList, AMOUNT_ORDER);
//		for (Product elem : mySortList) {
//			output = output + elem.getDisplayString() + "\n";
//		}
//		return output;
	}
	
	/**
	 * returns a all products sorted by short description
	 * @return String with all sorted products
	 */
	public String getSortedByShortDescription() {
		TreeMap<String, String> sortedMap = new TreeMap<String, String>();
		String output = "";
		for (ProductGroup pg : assortment.values()) {
			for (Iterator<Product> it = pg.getProductIterator(); it.hasNext(); ) {
				Product p = it.next();
				String outputString = 
					pg.getGroupName() + "\t" + p.getDisplayString() + "\n";
				sortedMap.put(p.getShortDescription(), outputString);
			}
		}
		
		for (String elem : sortedMap.values()) {
			output = output + elem;
		}
		return output;
	}
	
	/**
	 * returns a all products sorted by description
	 * @return String with all sorted products
	 */
	public String getSortedByDescription() {
		TreeMap<String, List<String>> sortedMap = new TreeMap<String, List<String>>();
		String output = "";
		for (ProductGroup pg : assortment.values()) {
			for (Iterator<Product> it = pg.getProductIterator(); it.hasNext(); ) {
				Product p = it.next();
				String outputString = 
					pg.getGroupName() + "\t" + p.getDisplayString() + "\n";
				List<String> l = sortedMap.get(p.getDescription());
				if (l == null) {
					sortedMap.put(p.getDescription(), l = new ArrayList<String>());
				}
				l.add(outputString);
			}
		}
		for (List<String> l : sortedMap.values()) {
			for (String elem : l) {
				output = output + elem;
			}
		}
		return output;
	}
	
//	/*
//	 * saves the complete warehouse to disk
//	 * 
//	 * @param filename the filename to save the warehouse to 
//	 */
//	public void serialize(String filename) {
//		/*
//		 * TODO:
//		 * exception-handling, maybe with a special exception?
//		 */
//		
//		FileOutputStream fs = null;
//		try {
//			fs = new FileOutputStream(filename);
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		}
//		
//	    try {
//	    	ObjectOutputStream os = new ObjectOutputStream(fs);
//	    	os.writeObject(assortment);
//	        os.close();
//	    } catch (IOException e) {
//	    	e.printStackTrace();
//	    }
//	}
//	
//	/*
//	 * retrieves a warehouse-file from disk
//	 */
//	public void deserialize(String filename) {
//		/*
//		 * TODO:
//		 * exception-handling, maybe with a special exception?
//		 */
//		
//		FileInputStream fs = null;
//		try {
//			fs = new FileInputStream(filename);
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		}
//		
//	    try {
//	    	ObjectInputStream is = new ObjectInputStream(fs);
//	    	Object object = is.readObject();
//	    	assert object instanceof TreeMap;
//	    	assortment = (TreeMap<String, ProductGroup>)object;
//	        is.close();
//	    } catch (IOException e) {
//	    	e.printStackTrace();
//	    } catch (ClassNotFoundException e) {
//	    	e.printStackTrace();
//	    }
//	}
	
	/**
	 * saves the complete warehouse into one file
	 */
	public void save(String filename) throws IOException {

		ProductGroup curPg;
		
		DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
											new FileOutputStream(filename)));
		Iterator<ProductGroup> pgIt = getPgIterator();
		while (pgIt.hasNext()) {
			curPg = pgIt.next();
			Iterator<Product> pIt = curPg.getProductIterator(); 
			while (pIt.hasNext()) {
				out.writeUTF(curPg.save() + "\\" + pIt.next().save());
			}
		}
		
		out.close();
	}

	
	/**
	 * restores the whole warehouse from one file
	 *
	 */
	public void restore(String filename) throws IOException, ProductException {
		
		DataInputStream in = new DataInputStream(new BufferedInputStream(
										new FileInputStream(filename)));
		String ProductLine = null;
		String[] PLineSplit = null;
		String[] PgData = null;

		while(in.available() > 0) {	// available Strings to read?
			ProductLine = in.readUTF();		// read String
			
			PLineSplit = ProductLine.split("\\\\");	
			PgData = PLineSplit[0].split(":");
			// exists ProductGroup already
			if (!assortment.containsKey(PgData[0])) {
				// no -> create one
				addProductGroup(PgData[0], Integer.parseInt(PgData[1]));
			}
			// add Product to ProductGroup
			assortment.get(PgData[0]).restore(ProductLine.substring(
												ProductLine.indexOf("\\")+1));
		}
		
		in.close();

	}
}
